/*
 * NodeIteratorImp.cpp
 *
 *  Created on: Apr 28, 2009
 *      Author: wrice
 */
#include "DOMCoreImp.h"
namespace DOMCoreImp {

struct NodeIteratorImp::Imp {

};

NodeIteratorImp::NodeIteratorImp(
		Node * root,
		unsigned long whatToShow,
		NodeFilter * filter,
		bool entityReferenceExpansion)
: root_(root)
, whatToShow_(whatToShow)
, filter_(filter)
, entityReferenceExpansion_(entityReferenceExpansion)
, referenceNode_(root)
, isPositionBeforeReferenceNode_(true)
{
}

Node * NodeIteratorImp::getRoot() {
	return root_;
}

unsigned long NodeIteratorImp::getWhatToShow() {
	return whatToShow_;
}

NodeFilter * NodeIteratorImp::getFilter() {
	return filter_;
}

bool NodeIteratorImp::getExpandEntityReferences() {
	return entityReferenceExpansion_;
}

unsigned long NodeIteratorImp::acceptNodeForWhatToShow( unsigned long whatToShow, Node * node ) {
	const unsigned short nodeType = node->getNodeType();

	if( nodeType == Node::ATTRIBUTE_NODE )
		return (NodeFilter::SHOW_ATTRIBUTE & whatToShow)
			? NodeFilter::FILTER_ACCEPT : NodeFilter::FILTER_SKIP;

	if( nodeType == Node::ELEMENT_NODE )
		return (NodeFilter::SHOW_ELEMENT & whatToShow)
			? NodeFilter::FILTER_ACCEPT : NodeFilter::FILTER_SKIP;

	if( nodeType == Node::TEXT_NODE )
		return (NodeFilter::SHOW_TEXT & whatToShow)
			? NodeFilter::FILTER_ACCEPT : NodeFilter::FILTER_SKIP;

	if( nodeType == Node::DOCUMENT_NODE )
		return (NodeFilter::SHOW_DOCUMENT & whatToShow)
			? NodeFilter::FILTER_ACCEPT : NodeFilter::FILTER_SKIP;

	return true;
}

Node * NodeIteratorImp::getNextNode( Node * from, Node * root, unsigned long whatToShow,
		NodeFilter * const nodeFilter, bool isRejected )
{
	Node * candidate = NULL;
	if( false == isRejected && from->hasChildNodes() )
		candidate = from->getFirstChild();
	else if( NULL != from->getNextSibling() )
		candidate = from->getNextSibling();
	else {
		Node * temp = from;
		do {
			if( root == temp ) return NULL;
			temp = temp->getParentNode();
			if( NULL != temp->getNextSibling() )
				candidate = temp->getNextSibling();
		} while( NULL == candidate );
	}

	const unsigned long confirm1 = acceptNodeForWhatToShow( whatToShow, candidate );
	if( confirm1 == NodeFilter::FILTER_SKIP )
		return getNextNode( candidate, root, whatToShow, nodeFilter, false );

	if( NULL != nodeFilter ) {
		const unsigned long confirm2 = nodeFilter->acceptNode( candidate );
		if( confirm2 == NodeFilter::FILTER_SKIP )
			return getNextNode( candidate, root, whatToShow, nodeFilter, false );
		if( confirm2 == NodeFilter::FILTER_REJECT )
			return getNextNode( candidate, root, whatToShow, nodeFilter, false );
	}

	return candidate;
}

Node * NodeIteratorImp::getPreviousNode( Node * from, Node * root, unsigned long whatToShow,
		NodeFilter * const nodeFilter, bool isRejected )
{
	Node * nextNode = root;
	Node * prevNode = NULL;
	while( nextNode != from && NULL != nextNode ) {
		prevNode = nextNode;
		nextNode = getNextNode( nextNode, root, whatToShow, nodeFilter, false );
	}
	return prevNode;
}

Node * NodeIteratorImp::nextNode() throw(DOMExceptionPtr) {
	Node * nextNode = getNextNode( referenceNode_, getRoot(), getWhatToShow(), getFilter(), false );
	if( NULL == nextNode )
		return NULL;

	if( true == isPositionBeforeReferenceNode_)
		isPositionBeforeReferenceNode_ = false;
	else
		referenceNode_ = nextNode;

	return referenceNode_;
}

Node * NodeIteratorImp::previousNode() throw(DOMExceptionPtr) {
	Node * prevNode = getPreviousNode( referenceNode_, getRoot(), getWhatToShow(), getFilter(), false);
	if( NULL == prevNode )
		return NULL;

	if( false == isPositionBeforeReferenceNode_)
		isPositionBeforeReferenceNode_ = true;
	else
		referenceNode_ = prevNode;

	return referenceNode_;
}

void NodeIteratorImp::detach() {
}

}
